/*
 * Copyright [yyyy] [name of copyright owner]
 * Licensed under the Apache License, Version 2.0 (the "License");
 * You may obtain a copy of the License at

 * http://www.apache.org/licenses/LICENSE-2.0

 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.flarebit.flarebarlib;

import com.github.florent37.viewanimator.ViewAnimator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.Image;
import ohos.agp.components.Text;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.render.BlendMode;
import ohos.agp.utils.Color;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.utils.TextAlignment;
import ohos.agp.window.service.Display;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;

import java.util.ArrayList;

/**
 * TabEventObject
 *
 * @author Vaibhav Patel
 * @since 2019-06-20
 */
public class FlareBar extends DirectionalLayout {
    private static final float SCALE_VALUE = 0.6F;
    private static final float ALPHA_VALUE = 0.5F;
    private static final float TRANSLATION_X = 40.0F;
    private static final float RATIO_5 = 0.5F;
    private static final float RATIO_8 = 0.8F;
    private static final float DARKNESS_299 = 0.299F;
    private static final float DARKNESS_587 = 0.587F;
    private static final float DARKNESS_114 = 0.114F;
    private static final float MAX = 255;
    private static final int DURATION = 300;
    private static final int WEIGHT = 3;
    private static final int WEIGHT_SELECT = 5;
    private static final int TEXT_SIZE = 40;
    private static final int BADGE_WIDTH = 60;
    private static final int IMAGE_WIDTH = 130;
    private static final int MARGIN_5 = 5;
    private static final int MARGIN_15 = 15;
    private static final int MARGIN_25 = 25;
    private static final int TABLIST_MAX = 4;
    private static final int DEFAULT_INDEX = 2;
    private boolean mIsBarVisible = true;
    private Context mContext;
    private ArrayList<Flaretab> mTabList;
    private int mSelectedIndex = 0;
    private TabEventObject.TabChangedListener mTabChangedListener;
    private ArrayList<DirectionalLayout> mTabLayoutList = new ArrayList<>();
    private ArrayList<Image> mTabImageList = new ArrayList<>();
    private ArrayList<Text> mTabTextList = new ArrayList<>();
    private ShapeElement mTabElement;
    private LayoutConfig mTabParams = new LayoutConfig(LayoutConfig.MATCH_CONTENT, LayoutConfig.MATCH_CONTENT);
    private Display mDisplay;
    private int mFlareBarHeight;
    private int mFlareBarWidth;

    /**
     * FlareBar
     *
     * @param context context
     */
    public FlareBar(Context context) {
        super(context);
        mContext = context;
        init();
    }

    /**
     * FlareBar
     *
     * @param context context
     * @param attrs attrs
     */
    public FlareBar(Context context, AttrSet attrs) {
        super(context, attrs);
        mContext = context;
        init();
    }

    /**
     * FlareBar
     *
     * @param context context
     * @param attrs attrs
     * @param defStyleAttr defStyleAttr
     */
    public FlareBar(Context context, AttrSet attrs, int defStyleAttr) {
        super(context, attrs);
        mContext = context;
        init();
    }

    /**
     * FlareBar
     *
     * @param context context
     * @param attrs attrs
     * @param defStyleAttr defStyleAttr
     * @param defStyleRes defStyleRes
     */
    public FlareBar(Context context, AttrSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs);
        mContext = context;
        init();
    }

    private void init() {
        setOrientation(HORIZONTAL);
        FlareBar.this.setAlignment(LayoutAlignment.BOTTOM);
    }

    /**
     * setTabList
     *
     * @param tabs tabs
     */
    public void setTabList(ArrayList<Flaretab> tabs) {
        mTabList = tabs;
        init();
    }

    /**
     * getTabList
     *
     * @return TabList
     */
    public ArrayList<Flaretab> getTabList() {
        return mTabList;
    }

    /**
     * setSelectedIndex
     *
     * @param selectedIndex selectedIndex
     */
    public void setSelectedIndex(int selectedIndex) {
        this.mSelectedIndex = selectedIndex;
    }

    /**
     * getSelectedIndex
     *
     * @return mSelectedIndex
     */
    public int getSelectedIndex() {
        return mSelectedIndex;
    }

    /**
     * attachTabs
     *
     * @param context context
     */
    public void attachTabs(Context context) {
        mDisplay = DisplayManager.getInstance().getDefaultDisplay(context).get();
        mFlareBarHeight = mDisplay.getAttributes().height;
        if (mTabList != null && mTabList.size() > 0) {
            for (int index = 0; index < mTabList.size(); index++) {
                final DirectionalLayout tabLayout = new DirectionalLayout(context);
                tabLayout.setOrientation(HORIZONTAL);
                mTabElement = new ShapeElement(context, ResourceTable.Graphic_tabs_corner_bg);
                mTabParams.weight = WEIGHT;
                if (index == mSelectedIndex) {
                    ShapeElement shapeElement = FlareUtils.getTintElement(mTabElement,
                            Color.getIntColor(mTabList.get(index).getTabColorString()), BlendMode.SRC_ATOP);
                    tabLayout.setBackground(shapeElement);
                    mTabParams.weight = WEIGHT_SELECT;
                }
                mTabParams.setMargins(0, MARGIN_25, 0, MARGIN_25);
                tabLayout.setLayoutConfig(mTabParams);

                final Image image = new Image(context);

                image.setImageElement(mTabList.get(index).getTabImage());
                image.setScale(SCALE_VALUE, SCALE_VALUE);
                LayoutConfig params = new LayoutConfig(IMAGE_WIDTH, IMAGE_WIDTH);
                image.setLayoutConfig(params);

                int btnColor;
                if (!isColorDark(Color.getIntColor(mTabList.get(index).getTabColorString()))) {
                    btnColor = FlareUtils.blendArgb(Color.getIntColor(mTabList.get(index).getTabColorString()),
                            Color.BLACK.getValue(), RATIO_5);
                } else {
                    btnColor = FlareUtils.blendArgb(Color.getIntColor(mTabList.get(index).getTabColorString()),
                            Color.WHITE.getValue(), RATIO_8);
                }
                if (index == mSelectedIndex) {
                    ShapeElement shapeElement = new ShapeElement();
                    image.setBackground(FlareUtils.getTintElement(shapeElement,
                            Color.getIntColor(mTabList.get(index).getTabColorString()), BlendMode.SRC_ATOP));
                }
                image.setScaleMode(Image.ScaleMode.INSIDE);
                final Text tabText = new Text(context);
                tabText.setText(mTabList.get(index).getTabText());
                tabText.setTextColor(new Color(btnColor));
                tabText.setTextAlignment(TextAlignment.CENTER);
                tabText.setTextSize(TEXT_SIZE);
                LayoutConfig tabParams = new LayoutConfig(LayoutConfig.MATCH_CONTENT, LayoutConfig.MATCH_PARENT);
                tabParams.setMargins(1, 0, MARGIN_5, 0);
                tabParams.alignment = TextAlignment.CENTER;
                tabParams.weight = 1;
                if (mTabList.size() > TABLIST_MAX) {
                    tabParams.weight = 0;
                }
                tabText.setLayoutConfig(tabParams);
                if (index != mSelectedIndex) {
                    tabText.setVisibility(HIDE);
                    image.setAlpha(1);
                } else {
                    image.setAlpha(ALPHA_VALUE);
                }

                tabLayout.addComponent(image);
                tabLayout.addComponent(tabText);
                if (mTabList.get(index).isBadgeGiven()) {
                    final Text badge = new Text(context);
                    badge.setText(mTabList.get(index).getBadge());
                    badge.setPadding(1, 1, 1, 1);
                    badge.setTextColor(Color.WHITE);
                    badge.setTextSize(TEXT_SIZE);
                    badge.setTextAlignment(TextAlignment.CENTER);
                    badge.setBackground(new ShapeElement(context, ResourceTable.Graphic_badge_round_bg));
                    tabParams = new LayoutConfig(BADGE_WIDTH, BADGE_WIDTH);
                    tabParams.alignment = LayoutAlignment.CENTER;
                    badge.setLayoutConfig(tabParams);
                    tabLayout.addComponent(badge);
                }
                this.addComponent(tabLayout);
                final int finalI = index;

                mTabLayoutList.add(tabLayout);
                mTabImageList.add(image);
                mTabTextList.add(tabText);

                image.setClickedListener(new ClickedListener() {
                    @Override
                    public void onClick(Component component) {
                        handleTabTouch(tabLayout, finalI);
                    }
                });
                tabLayout.setClickedListener(new ClickedListener() {
                    @Override
                    public void onClick(Component component) {
                        handleTabTouch(tabLayout, finalI);
                    }
                });
            }
        }
    }

    private void handleTabTouch(DirectionalLayout tabLayout, int finalI) {
        new TabEventObject(mTabChangedListener).tabChangedListener.onTabChanged(tabLayout, finalI, mSelectedIndex);

        mTabTextList.get(mSelectedIndex).setVisibility(HIDE);
        mTabImageList.get(mSelectedIndex).setScale(SCALE_VALUE, SCALE_VALUE);
        mTabParams.weight = WEIGHT;
        mTabLayoutList.get(mSelectedIndex).setLayoutConfig(mTabParams);

        ShapeElement shapeElement = new ShapeElement();
        shapeElement.setRgbColor(RgbColor.fromRgbaInt(Color.TRANSPARENT.getValue()));
        mTabLayoutList.get(mSelectedIndex).setBackground(shapeElement);
        mTabImageList.get(mSelectedIndex).setAlpha(1);
        mTabElement = new ShapeElement(getContext(), ResourceTable.Graphic_tabs_corner_bg);
        ShapeElement tabDrawableElement = FlareUtils.getTintElement(mTabElement,
                Color.getIntColor(mTabList.get(finalI).getTabColorString()), BlendMode.SRC_ATOP);
        tabLayout.setBackground(tabDrawableElement);

        int btnColor;
        if (!isColorDark(Color.getIntColor(mTabList.get(finalI).getTabColorString()))) {
            btnColor = FlareUtils.blendArgb(Color.getIntColor(mTabList.get(finalI).getTabColorString()),
                    Color.BLACK.getValue(), RATIO_5);
        } else {
            btnColor = FlareUtils.blendArgb(Color.getIntColor(mTabList.get(finalI).getTabColorString()),
                    Color.WHITE.getValue(), RATIO_8);
        }
        ShapeElement tabImagesElement = new ShapeElement();
        mTabImageList.get(finalI)
                .setBackground(FlareUtils.getTintElement(tabImagesElement, btnColor, BlendMode.SRC_ATOP));
        mTabTextList.get(finalI).setVisibility(VISIBLE);

        mSelectedIndex = finalI;
        mTabParams.weight = WEIGHT_SELECT;
        mTabImageList.get(finalI).setAlpha(ALPHA_VALUE);
        mTabLayoutList.get(finalI).setLayoutConfig(mTabParams);
        ViewAnimator.animate(mTabImageList.get(finalI)).scale(SCALE_VALUE, SCALE_VALUE).duration(DURATION).start();
        ViewAnimator.animate(mTabLayoutList.get(finalI)).translationX(TRANSLATION_X, 0).duration(DURATION).start();
    }

    /**
     * removeBadge
     *
     * @param tabIndex tabIndex
     */
    public void removeBadge(int tabIndex) {
        mTabLayoutList.get(tabIndex).removeComponentAt(DEFAULT_INDEX);
    }

    /**
     * setTabsTextColor
     *
     * @param textColor textColor
     */
    public void setTabsTextColor(int textColor) {
        for (Text txt : mTabTextList) {
            txt.setTextColor(new Color(textColor));
        }
    }

    /**
     * selectTab
     *
     * @param index index
     */
    public void selectTab(int index) {
        mSelectedIndex = index;
        this.removeAllComponents();
        mTabLayoutList.clear();
        mTabTextList.clear();
        mTabImageList.clear();
        attachTabs(mContext);
    }

    /**
     * setBarBackgroundColor
     *
     * @param color color
     */
    public void setBarBackgroundColor(int color) {
        ShapeElement shapeElement = new ShapeElement();
        shapeElement.setRgbColor(RgbColor.fromRgbaInt(color));
        this.setBackground(shapeElement);
    }

    /**
     * getBarBackgroundColor
     *
     * @return colorInt
     */
    public int getBarBackgroundColor() {
        ShapeElement viewElement = (ShapeElement) this.getBackgroundElement();
        RgbColor[] viewColor = viewElement.getRgbColors();
        int colorInt = viewColor[0].asArgbInt();
        return colorInt;
    }

    /**
     * setTabChangedListener
     *
     * @param tabChangedListener tabChangedListener
     */
    public void setTabChangedListener(TabEventObject.TabChangedListener tabChangedListener) {
        this.mTabChangedListener = tabChangedListener;
        new TabEventObject(tabChangedListener);
    }

    private boolean isColorDark(int color) {
        double darkness = 1 - (DARKNESS_299 * FlareUtils.red(color) + DARKNESS_587 * FlareUtils.green(color)
                + DARKNESS_114 * FlareUtils.blue(color)) / MAX;
        if (darkness < ALPHA_VALUE) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * hideBar
     */
    public void hideBar() {
        mDisplay = DisplayManager.getInstance().getDefaultDisplay(mContext).get();
        mFlareBarHeight = mDisplay.getAttributes().height;
        mIsBarVisible = false;
        new AnimatorProperty().setTarget(this)
                .moveFromY(mFlareBarHeight - getHeight())
                .moveToY(mFlareBarHeight)
                .setDuration(DURATION)
                .start();
    }

    /**
     * showBar
     */
    public void showBar() {
        mDisplay = DisplayManager.getInstance().getDefaultDisplay(mContext).get();
        mFlareBarHeight = mDisplay.getAttributes().height;
        mFlareBarWidth = mDisplay.getAttributes().width;
        mIsBarVisible = true;
        new AnimatorProperty().setTarget(this)
                .moveFromY(mFlareBarHeight)
                .moveToY(mFlareBarHeight>mFlareBarWidth ? mFlareBarHeight - getHeight() : mFlareBarHeight - getHeight()-120)
                .setDuration(DURATION)
                .start();
    }

    /**
     * isBarVisible
     *
     * @return Bar status
     */
    public boolean isBarVisible() {
        return mIsBarVisible;
    }
}
